package xin.marcher.module.message.repository;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Repository;
import xin.marcher.module.common.constants.CoreConstant;
import xin.marcher.module.common.constants.message.AbstractRedisKeyConstants;
import xin.marcher.module.common.domain.BaseDO;
import xin.marcher.module.common.enums.DelFlagEnum;
import xin.marcher.module.common.enums.message.MessageTypeEnum;
import xin.marcher.module.common.exception.BaseBizException;
import xin.marcher.module.common.exception.CommonErrorCodeEnum;
import xin.marcher.module.common.message.DataChangeMessage;
import xin.marcher.module.message.converter.DataMessageConverter;
import xin.marcher.module.message.domain.bo.DataChangeMessageConfigBO;
import xin.marcher.module.message.domain.bo.DataMessageBO;
import xin.marcher.module.message.domain.bo.DataSendMessageBO;
import xin.marcher.module.message.domain.entity.*;
import xin.marcher.module.message.manager.common.RedisReadWriteManager;
import xin.marcher.module.message.mapper.*;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 
 */
@Repository
public class DataChangeRepository {

    @Resource
    private DataChangeListenConfigMapper dataChangeListenConfigMapper;

    @Resource
    private DataChangeColumnConfigMapper dataChangeColumnConfigMapper;

    @Resource
    private DataChangeMessageConfigMapper dataChangeMessageConfigMapper;

    @Resource
    private DataMessageDetailMapper dataMessageDetailMapper;

    @Resource
    private DataTraceListenConfigMapper dataTraceListenConfigMapper;

    @Resource
    private DataMessageConverter dataMessageConverter;

    @Resource
    private RedisReadWriteManager redisReadWriteManager;

    /**
     * 获取某个消息对应的外部消息对象
     *
     * @param messageNo
     * @return
     */
    public DataMessageDetailDO getDataMessageDetail(String messageNo) {

        LambdaQueryWrapper<DataMessageDetailDO> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(DataMessageDetailDO::getMessageNo, messageNo);

        return dataMessageDetailMapper.selectOne(queryWrapper);
    }

    /**
     * 存储外部消息的数据信息
     *
     * @param dataMessageBO
     */
    public void saveDataMessageDetail(DataMessageBO dataMessageBO) {
        DataMessageDetailDO dataMessageDetailDO = dataMessageConverter.converterDO(dataMessageBO);

        int count = dataMessageDetailMapper.insert(dataMessageDetailDO);

        if (count <= 0) {
            throw new BaseBizException(CommonErrorCodeEnum.SQL_ERROR);
        }
    }

    /**
     * 存储外部消息的数据信息
     *
     * @param dataMessageBOS
     */
    public void saveDataMessageDetail(List<DataMessageBO> dataMessageBOS) {
        List<DataMessageDetailDO> dataMessageDetailDOS = dataMessageConverter.converterDOList(dataMessageBOS);

        int count = dataMessageDetailMapper.insertBatch(dataMessageDetailDOS);

        if (count <= 0) {
            throw new BaseBizException(CommonErrorCodeEnum.SQL_ERROR);
        }
    }

    /**
     * 获取需要发送的外部消息对象
     *
     * @param dataMessageBO
     */
    public List<DataSendMessageBO> getDataChangeMessageConfig(DataMessageBO dataMessageBO) {
        List<DataSendMessageBO> dataChangeMessageList = new ArrayList<>();
        DataChangeListenConfigDO dataChangeListenConfig = getDataChangeListenConfig(dataMessageBO.getTableName());
        if (!Objects.isNull(dataChangeListenConfig)) {

            // 获取配置的需要发送的外部消息信息
            List<DataChangeMessageConfigDO> dataChangeMessageConfigList =
                    getMessageConfigByListenId(dataChangeListenConfig.getId(), MessageTypeEnum.EXTERNAL_MESSAGE);

            if (!CollectionUtils.isEmpty(dataChangeMessageConfigList)) {

                DataSendMessageBO dataSendMessageBO = new DataSendMessageBO();

                JSONObject tableDataJson = JSONObject.parseObject(dataMessageBO.getTableDataJson());

                List<String> updateColumns = converterList(dataMessageBO.getDiffDataArr());

                for (DataChangeMessageConfigDO messageConfigDO : dataChangeMessageConfigList) {
                    DataChangeMessage dataChangeMessage = dataMessageConverter.converter(dataMessageBO);

                    dataChangeMessage.setUpdateColumns(updateColumns);
                    // 获取得到需要发送的字段信息
                    String[] notifyColumnArr = messageConfigDO.getNotifyColumn().split(CoreConstant.COMMA);
                    List<DataChangeMessage.ColumnValue> columnValueList = new ArrayList<>();
                    for (String notifyColumn : notifyColumnArr) {
                        columnValueList.add(
                                new DataChangeMessage.ColumnValue(notifyColumn, tableDataJson.getString(notifyColumn))
                        );
                    }
                    dataChangeMessage.setColumnValues(columnValueList);
                    dataSendMessageBO.setDataChangeMessage(dataChangeMessage);
                    dataSendMessageBO.setDataChangeMessageConfigBO(dataMessageConverter.converterBO(messageConfigDO));
                    dataChangeMessageList.add(dataSendMessageBO);
                }
            }
        }
        return dataChangeMessageList;
    }

    /**
     * 将变化的diff数据转换为消息体数据结构
     *
     * @param diffDataArr
     * @return
     */
    private List<String> converterList(String diffDataArr) {
        List<String> updateColumns = new ArrayList<>();
        String[] split = diffDataArr.split(CoreConstant.COMMA);
        if (!Objects.isNull(split) && split.length > 0) {
            updateColumns.addAll(Arrays.asList(split));
        }
        return updateColumns;
    }

    /**
     * 获取对应的表配置信息
     *
     * @param tableName
     * @return
     */
    public DataChangeListenConfigDO getDataChangeListenConfig(String tableName) {
        LambdaQueryWrapper<DataChangeListenConfigDO> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(DataChangeListenConfigDO::getTableName, tableName);
        queryWrapper.eq(DataChangeListenConfigDO::getFilterFlag, DelFlagEnum.EFFECTIVE.getCode());
        return dataChangeListenConfigMapper.selectOne(queryWrapper);
    }

    /**
     * 消息发送完成后进行删除
     *
     * @param messageNo
     */
    public void deleteDataMessageDetail(String messageNo) {
        LambdaUpdateWrapper<DataMessageDetailDO> updateWrapper = Wrappers.lambdaUpdate();
        updateWrapper.eq(DataMessageDetailDO::getMessageNo, messageNo);

        dataMessageDetailMapper.delete(updateWrapper);
    }

    /**
     * 根据表名获取监听配置信息
     *
     * @param tableName
     * @return
     */
    public Optional<DataChangeListenConfigDO> getListenConfigByTableFromDB(String tableName) {
        LambdaQueryWrapper<DataChangeListenConfigDO> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(DataChangeListenConfigDO::getTableName, tableName)
                .eq(BaseDO::getDelFlag, DelFlagEnum.EFFECTIVE.getCode());

        DataChangeListenConfigDO listenConfigDO = dataChangeListenConfigMapper.selectOne(queryWrapper);
        return Objects.isNull(listenConfigDO) ? Optional.empty() : Optional.of(listenConfigDO);
    }

    /**
     * 根据表名获取监听配置信息
     *
     * @param tableName
     * @return
     */
    public DataChangeListenConfigDO getListenConfigByTable(String tableName) {
        Optional<DataChangeListenConfigDO> optional =
                redisReadWriteManager.getRedisStringDataByCache(tableName, DataChangeListenConfigDO.class,
                        AbstractRedisKeyConstants::getListenConfigStringKey,
                        this::getListenConfigByTableFromDB);
        return optional.orElse(null);
    }

    /**
     * 获取监听变更字段配置表信息
     *
     * @param id
     * @return
     */
    public Optional<List<DataChangeColumnConfigDO>> getColumnConfigByListenIdFromDB(Long id) {
        LambdaQueryWrapper<DataChangeColumnConfigDO> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(DataChangeColumnConfigDO::getListenId, id)
                .eq(BaseDO::getDelFlag, DelFlagEnum.EFFECTIVE.getCode());

        List<DataChangeColumnConfigDO> columnConfigDOS = dataChangeColumnConfigMapper.selectList(queryWrapper);
        return CollectionUtils.isEmpty(columnConfigDOS) ? Optional.empty() : Optional.of(columnConfigDOS);
    }

    /**
     * 获取监听变更字段配置表信息
     *
     * @param id
     * @return
     */
    public List<DataChangeColumnConfigDO> getColumnConfigByListenId(Long id) {
        Optional<List<DataChangeColumnConfigDO>> optional =
                redisReadWriteManager.listRedisStringDataByCache(id, DataChangeColumnConfigDO.class,
                        AbstractRedisKeyConstants::getColumnConfigStringKey,
                        this::getColumnConfigByListenIdFromDB);
        return optional.orElse(null);
    }

    /**
     * 查询数据变更消息列表
     *
     * @param id
     * @return
     */
    public Optional<List<DataChangeMessageConfigDO>> getMessageConfigByListenIdFromDB(Long id) {
        LambdaQueryWrapper<DataChangeMessageConfigDO> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(DataChangeMessageConfigDO::getListenId, id)
                .eq(BaseDO::getDelFlag, DelFlagEnum.EFFECTIVE.getCode());

        List<DataChangeMessageConfigDO> messageConfigDOS = dataChangeMessageConfigMapper.selectList(queryWrapper);
        return CollectionUtils.isEmpty(messageConfigDOS) ? Optional.empty() : Optional.of(messageConfigDOS);
    }

    /**
     * 获取监听表消息模型配置
     *
     * @param id
     * @return
     */
    public List<DataChangeMessageConfigBO> getMessageConfigBOByListenId(Long id) {
        //获取监听表消息模型配置
        return dataMessageConverter.converterBOList(getMessageConfigByListenId(id, null));
    }

    /**
     * 获取监听表消息模型配置
     *
     * @param id
     * @param messageTypeEnum
     * @return
     */
    public List<DataChangeMessageConfigDO> getMessageConfigByListenId(Long id, MessageTypeEnum messageTypeEnum) {
        //获取监听表消息模型配置
        Optional<List<DataChangeMessageConfigDO>> optional =
                redisReadWriteManager.listRedisStringDataByCache(id,
                        DataChangeMessageConfigDO.class,
                        AbstractRedisKeyConstants::getMessageConfigStringKey,
                        this::getMessageConfigByListenIdFromDB);

        // 如果未指定是内部消息还是外部消息，则不需要过滤
        if (Objects.isNull(messageTypeEnum)) {
            return optional.orElse(null);
        }

        return optional.map(dataChangeMessageConfigDOS -> dataChangeMessageConfigDOS.stream()
                .filter(messageConfigBO -> messageTypeEnum.getCode().equals(messageConfigBO.getMessageType()))
                .collect(Collectors.toList())).orElse(null);
    }

    /**
     * 根据表名获取溯源配置信息
     *
     * @param tableName
     * @return
     */
    public Optional<DataTraceListenConfigDO> getTraceListenConfigByTableFromDB(String tableName) {
        LambdaQueryWrapper<DataTraceListenConfigDO> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(DataTraceListenConfigDO::getTableName, tableName)
                .eq(BaseDO::getDelFlag, DelFlagEnum.EFFECTIVE.getCode());

        DataTraceListenConfigDO traceListenConfigDO = dataTraceListenConfigMapper.selectOne(queryWrapper);
        return Objects.isNull(traceListenConfigDO) ? Optional.empty() : Optional.of(traceListenConfigDO);
    }

    /**
     * 根据表名获取溯源配置信息
     *
     * @param tableName
     * @return
     */
    public DataTraceListenConfigDO getTraceListenConfigByTable(String tableName) {
        Optional<DataTraceListenConfigDO> optional =
                redisReadWriteManager.getRedisStringDataByCache(tableName, DataTraceListenConfigDO.class,
                        AbstractRedisKeyConstants::getTraceListenConfigStringKey,
                        this::getTraceListenConfigByTableFromDB);
        return optional.orElse(null);
    }

}
